#!/bin/sh

e2e_test_install() {
  NODE_LABEL_KEY="$(random_string)"
  NODE_LABEL_VALUE="$(random_string)"

  DISTRIBUTEDLOGS_NAME=distributedlogs
  init_expandable_storage_class

  create_or_replace_cluster "$CLUSTER_NAME-for-distributedlogs" "$CLUSTER_NAMESPACE" "1" \
    --set cluster.create=false \
    --set configurations.create=false \
    --set instanceProfiles=null \
    --set distributedLogs.enabled=true \
    --set distributedLogs.create=true \
    --set-string cluster.distributedLogs.sgDistributedLogs="$DISTRIBUTEDLOGS_NAME" \
    --set-string "distributedLogs.scheduling.nodeSelector.$NODE_LABEL_KEY=$NODE_LABEL_VALUE" \
    --set-string distributedLogs.persistentVolume.size=128Mi \
    --set distributedLogs.persistentVolume.storageClass="$EXPANDABLE_STORAGE_CLASSNAME"

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  wait_pods_running "$CLUSTER_NAMESPACE" 1

  OPERATOR_DISTRIBUTEDLOGS_CR="$(kubectl get sgdistributedlogs.stackgres.io -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME" -o json \
    | jq 'del(.metadata.creationTimestamp) | del(.metadata.generation) | del(.metadata.resourceVersion) | del(.metadata.selfLink) | del(.metadata.uid)' )"

  echo_raw "$OPERATOR_DISTRIBUTEDLOGS_CR" > "$LOG_PATH/distributed-logs-cr.json"

  OPERATOR_DISTRIBUTEDLOGS="$(cat "$LOG_PATH/distributed-logs-cr.json" \
    | jq 'del(.apiVersion) | del(.kind) | del(.status)' )"

  echo_raw "$OPERATOR_DISTRIBUTEDLOGS" > "$LOG_PATH/distributed-logs.json"
}

e2e_test() {
  run_test "Check that a created distributed logs can be accessed directly through the API" check_distributed_logs_directly

  run_test "Check that a created distributed logs is included in the response" check_distributed_logs_in_list

  run_test "Check that a distributed logs was removed after its deletion in the API" check_distributed_logs_removed

  run_test "Check distributed logs is created with the API and is visible in the API" test_api_created_distributed_logs_is_visible

  run_test "Check distributed logs is updated with the API are reflected in the API" test_api_updated_distributed_logs_is_visible

  run_test "Check distributed logs is deleted with the API are reflected in the API" test_api_delete_distributed_logs_is_visible

  run_test "Constraint violations should be detected" test_constraint_violation_api_error

  run_test "User with wrong credentials should not be authenticated" test_authentication_api_error
}

check_distributed_logs_in_list() {
  if run_curl -r "stackgres/sgdistributedlogs" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\" and .metadata.name == \"$DISTRIBUTEDLOGS_NAME\") | .metadata.name" \
    | grep -q "^$DISTRIBUTEDLOGS_NAME$"
  then
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME included in json response"
    return 0
  else
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME not included in json response"
    return 1
  fi
}

get_distributed_logs_http_status() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdistributedlogs/$DISTRIBUTEDLOGS_NAME" -e "-LI -o /dev/null -w %{http_code}"
}

get_distributed_logs_pod_count() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdistributedlogs/$DISTRIBUTEDLOGS_NAME" | jq '.pods | length'
}

check_distributed_logs_directly() {
  local HTTP_STATUS

  HTTP_STATUS="$(get_distributed_logs_http_status)"

  if [ "$HTTP_STATUS" -eq "200" ]
  then
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME was found bye the api"
    return 0
  else
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME was not found bye the api"
    return 1
  fi
}

remove_distributed_logs_cr_if_exists() {
  if kubectl get sgdistributedlogs.stackgres.io -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME"
  then
    kubectl delete sgdistributedlogs.stackgres.io -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME"

    wait_until eval '! kubectl get sgdistributedlogs.stackgres.io -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME"'
  fi
}

check_distributed_logs_removed() {
  local HTTP_STATUS

  remove_distributed_logs_cr_if_exists

  if run_curl -r "stackgres/sgdistributedlogs" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\" and .metadata.name == \"$DISTRIBUTEDLOGS_NAME\") | .metadata.name" \
    | grep -q "^$DISTRIBUTEDLOGS_NAME$"
  then
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME wasn't removed from cache"
    return 1
  else
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME was removed from cache"
    return 0
  fi

  HTTP_STATUS="$(run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdistributedlogs/$DISTRIBUTEDLOGS_NAME" -e "-LI -o /dev/null -w %{http_code}")"

  if [ "$HTTP_STATUS" -eq "404" ]
  then
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME was not found by the api"
    return 0
  else
    echo "Distributred logs $DISTRIBUTEDLOGS_NAME was found by the api"
    return 1
  fi
}

create_distributed_logs_with_api() {
  local HTTP_STATUS

  remove_distributed_logs_cr_if_exists

  HTTP_STATUS="$(run_curl -r "stackgres/sgdistributedlogs" -d "$LOG_PATH/distributed-logs.json" -e '-X POST -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgdistributedlogs" -d "$LOG_PATH/distributed-logs.json" -e '-X POST')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_created_distributed_logs_is_visible() {
  create_distributed_logs_with_api

  if kubectl get sgdistributedlogs.stackgres.io -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME"
  then
    echo "Distributred logs created with the API"
  else
    echo "Distributred logs CR was not created"
    return 1
  fi

  check_distributed_logs_directly
}

update_distributed_logs_parameter_with_api() {
  local HTTP_STATUS

  local FIELDS
  local FIELD
  for FIELD in $(echo "$1" | tr '.' '\n')
  do
    FIELDS="$FIELDS[\"$FIELD\"]"
  done
  UPDATED_DISTRIBUTEDLOGS="$(cat "$LOG_PATH/distributed-logs.json" | jq ".spec$FIELDS = $2")"
  echo_raw "$UPDATED_DISTRIBUTEDLOGS" > "$LOG_PATH/updated-distributed-logs.json"

  HTTP_STATUS="$(run_curl -r "stackgres/sgdistributedlogs" -d "$LOG_PATH/updated-distributed-logs.json" -e '-X PUT -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgdistributedlogs" -d "$LOG_PATH/updated-distributed-logs.json" -e '-X PUT')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_updated_distributed_logs_is_visible() {
  update_distributed_logs_parameter_with_api 'persistentVolume.size' '"256Mi"'

  if kubectl get sgdistributedlogs.stackgres.io -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME" -o jsonpath='{.spec.persistentVolume.size}' \
    | grep -q "^256Mi$"
  then
    echo "Distributred logs updates are being reflected"
  else
    echo "Distributred logs updates aren't being reflected"
    return 1
  fi

  if run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdistributedlogs/$DISTRIBUTEDLOGS_NAME" | jq '.spec.persistentVolume.size' -r \
    | grep -q "^256Mi$"
  then
    echo "Distributred logs updates are being reflected in the api"
  else
    echo "Distributred logs updates aren't being reflected in the api"
    return 1
  fi
}

delete_distributed_logs_with_api() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sgdistributedlogs" -d "$LOG_PATH/distributed-logs.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgdistributedlogs" -d "$LOG_PATH/distributed-logs.json" -e '-X PUT')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_delete_distributed_logs_is_visible() {
  delete_distributed_logs_with_api

  if wait_until eval '[ "$(get_distributed_logs_http_status)" = "404" ]'
  then
    echo "Distributred logs removed from the API"
  else
    echo "Distributred logs wasn't removed from the API"
    return 1
  fi
}

test_constraint_violation_api_error() {
  local HTTP_STATUS

  INVALID_DISTRIBUTEDLOGS="$(cat "$LOG_PATH/distributed-logs.json" | jq '.spec.persistentVolume.size = null' )"
  echo_raw "$INVALID_DISTRIBUTEDLOGS" > "$LOG_PATH/invalid-distributed-logs.json"

  HTTP_STATUS="$(run_curl -r "stackgres/sgdistributedlogs" -n "$CLUSTER_NAMESPACE"  -d "$LOG_PATH/invalid-distributed-logs.json" -e '-X POST -w %{http_code} -o /dev/null')"

  assert_string_equal "422" "$HTTP_STATUS"

  ERROR_RESPONSE="$(run_curl -r "stackgres/sgdistributedlogs" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-distributed-logs.json" -e '-X POST')"

  EXPECTED_ERROR_TYPE="constraint-violation"
  EXPECTED_ERROR_TITLE="do not comply with the syntactic rules"
  EXPECTED_ERROR_DETAIL="must be specified"
  EXPECTED_ERROR_FIELD="spec.persistentVolume.size"

  assert_api_error "$ERROR_RESPONSE"

  INVALID_DISTRIBUTEDLOGS_NAME="$(cat "$LOG_PATH/distributed-logs.json" | jq '.metadata.name = "test-pg12.8"' )"

  echo "$INVALID_DISTRIBUTEDLOGS_NAME" > "$LOG_PATH/invalid-distributed-logs-name.json"

  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sgdistributedlogs" -n "$CLUSTER_NAMESPACE"  -d "$LOG_PATH/invalid-distributed-logs-name.json" -e '-X POST -w %{http_code} -o /dev/null')"

  assert_string_equal "422" "$HTTP_STATUS"

  ERROR_RESPONSE="$(run_curl -r "stackgres/sgdistributedlogs" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-distributed-logs-name.json" -e '-X POST')"

  EXPECTED_ERROR_TYPE="constraint-violation"
  EXPECTED_ERROR_TITLE="Some fields do not comply with the syntactic rules"
  EXPECTED_ERROR_DETAIL="metadata.name in body should match '^[a-z]([-a-z0-9]*[a-z0-9])?$'"
  EXPECTED_ERROR_FIELD="metadata.name"

  assert_api_error "$ERROR_RESPONSE"
}

test_authentication_api_error() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdistributedlogs"  -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdistributedlogs/$DISTRIBUTEDLOGS_NAME" -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdistributedlogs" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/distributed-logs.json" -e '-X POST -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdistributedlogs" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/distributed-logs.json" -e '-X PUT -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdistributedlogs" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/distributed-logs.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  check_authentication_error
}

check_authentication_error() {
  if [ "$HTTP_STATUS" = "401" ]
  then
    echo "Request returned expected authentication error"
    return 0
  else
    echo "Request returned unexpected response status $HTTP_STATUS instead of the expected authentication error."
    return 1
  fi
}